home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / 92052tar.gz / 920528.tar / ip.c < prev    next >
C/C++ Source or Header  |  1992-01-08  |  14KB  |  539 lines

  1. /* @(#) $Header: ip.c,v 1.6 92/01/08 13:45:14 deyke Exp $ */
  2.  
  3. /* Upper half of IP, consisting of send/receive primitives, including
  4.  * fragment reassembly, for higher level protocols.
  5.  * Not needed when running as a standalone gateway.
  6.  * Copyright 1991 Phil Karn, KA9Q
  7.  */
  8. #include "global.h"
  9. #include "mbuf.h"
  10. #include "timer.h"
  11. #include "internet.h"
  12. #include "netuser.h"
  13. #include "iface.h"
  14. #include "pktdrvr.h"
  15. #include "ip.h"
  16. #include "icmp.h"
  17.  
  18. static struct mbuf *fraghandle __ARGS((struct ip *ip,struct mbuf *bp));
  19. static void ip_timeout __ARGS((void *arg));
  20. static void free_reasm __ARGS((struct reasm *rp));
  21. static void freefrag __ARGS((struct frag *fp));
  22. static struct reasm *lookup_reasm __ARGS((struct ip *ip));
  23. static struct reasm *creat_reasm __ARGS((struct ip *ip));
  24. static struct frag *newfrag __ARGS((int offset,int last,struct mbuf *bp));
  25.  
  26. struct mib_entry Ip_mib[20] = {
  27.     "",                     0,
  28.     "ipForwarding",         1,
  29.     "ipDefaultTTL",         MAXTTL,
  30.     "ipInReceives",         0,
  31.     "ipInHdrErrors",        0,
  32.     "ipInAddrErrors",       0,
  33.     "ipForwDatagrams",      0,
  34.     "ipInUnknownProtos",    0,
  35.     "ipInDiscards",         0,
  36.     "ipInDelivers",         0,
  37.     "ipOutRequests",        0,
  38.     "ipOutDiscards",        0,
  39.     "ipOutNoRoutes",        0,
  40.     "ipReasmTimeout",       TLB,
  41.     "ipReasmReqds",         0,
  42.     "ipReasmOKs",           0,
  43.     "ipReasmFails",         0,
  44.     "ipFragOKs",            0,
  45.     "ipFragFails",          0,
  46.     "ipFragCreates",        0,
  47. };
  48.  
  49. struct reasm *Reasmq;
  50. static struct raw_ip *Raw_ip;
  51.  
  52. #define INSERT  0
  53. #define APPEND  1
  54. #define PREPEND 2
  55.  
  56. /* Send an IP datagram. Modeled after the example interface on p 32 of
  57.  * RFC 791
  58.  */
  59. int
  60. ip_send(source,dest,protocol,tos,ttl,bp,length,id,df)
  61. int32 source;                   /* source address */
  62. int32 dest;                     /* Destination address */
  63. char protocol;                  /* Protocol */
  64. char tos;                       /* Type of service */
  65. char ttl;                       /* Time-to-live */
  66. struct mbuf *bp;                /* Data portion of datagram */
  67. int16 length;                   /* Optional length of data portion */
  68. int16 id;                       /* Optional identification */
  69. char df;                        /* Don't-fragment flag */
  70. {
  71.     struct mbuf *tbp;
  72.     struct ip ip;                   /* IP header */
  73.     static int16 id_cntr = 0;       /* Datagram serial number */
  74.     struct phdr phdr;
  75.  
  76.     ipOutRequests++;
  77.  
  78.     if(source == INADDR_ANY)
  79.         source = locaddr(dest);
  80.     if(length == 0 && bp != NULLBUF)
  81.         length = len_p(bp);
  82.     if(id == 0)
  83.         id = id_cntr++;
  84.     if(ttl == 0)
  85.         ttl = ipDefaultTTL;
  86.  
  87.     /* Fill in IP header */
  88.     ip.version = IPVERSION;
  89.     ip.tos = tos;
  90.     ip.length = IPLEN + length;
  91.     ip.id = id;
  92.     ip.offset = 0;
  93.     ip.flags.mf = 0;
  94.     ip.flags.df = df;
  95.     ip.flags.congest = 0;
  96.     ip.ttl = ttl;
  97.     ip.protocol = protocol;
  98.     ip.source = source;
  99.     ip.dest = dest;
  100.     ip.optlen = 0;
  101.     if((tbp = htonip(&ip,bp,IP_CS_NEW)) == NULLBUF){
  102.         free_p(bp);
  103.         return -1;
  104.     }
  105.     if((bp = pushdown(tbp,sizeof(phdr))) == NULLBUF){
  106.         free_p(tbp);
  107.         return -1;
  108.     }
  109.     if(ismyaddr(ip.dest)){
  110.         /* Pretend it has been sent by the loopback interface before
  111.          * it appears in the receive queue
  112.          */
  113.         phdr.iface = &Loopback;
  114.         Loopback.ipsndcnt++;
  115.         Loopback.rawsndcnt++;
  116.         Loopback.lastsent = secclock();
  117.     } else
  118.         phdr.iface = NULLIF;
  119.     phdr.type = CL_NONE;
  120.     memcpy(&bp->data[0],(char *)&phdr,sizeof(phdr));
  121.     enqueue(&Hopper,bp);
  122.     return 0;
  123. }
  124.  
  125. /* Reassemble incoming IP fragments and dispatch completed datagrams
  126.  * to the proper transport module
  127.  */
  128. void
  129. ip_recv(iface,ip,bp,rxbroadcast)
  130. struct iface *iface;    /* Incoming interface */
  131. struct ip *ip;          /* Extracted IP header */
  132. struct mbuf *bp;        /* Data portion */
  133. int rxbroadcast;        /* True if received on subnet broadcast address */
  134. {
  135.     /* Function to call with completed datagram */
  136.     register struct raw_ip *rp;
  137.     struct mbuf *bp1,*tbp;
  138.     int rxcnt = 0;
  139.     register struct iplink *ipp;
  140.  
  141.     /* If we have a complete packet, call the next layer
  142.      * to handle the result. Note that fraghandle passes back
  143.      * a length field that does NOT include the IP header
  144.      */
  145.     if((bp = fraghandle(ip,bp)) == NULLBUF)
  146.         return;         /* Not done yet */
  147.  
  148.     ipInDelivers++;
  149.  
  150.     for(rp = Raw_ip;rp != NULLRIP;rp = rp->next){
  151.         if(rp->protocol != ip->protocol)
  152.             continue;
  153.         rxcnt++;
  154.         /* Duplicate the data portion, and put the header back on */
  155.         dup_p(&bp1,bp,0,len_p(bp));
  156.         if(bp1 != NULLBUF && (tbp = htonip(ip,bp1,IP_CS_OLD)) != NULLBUF){
  157.             enqueue(&rp->rcvq,tbp);
  158.             if(rp->r_upcall != NULLVFP)
  159.                 (*rp->r_upcall)(rp);
  160.         } else {
  161.             free_p(bp1);
  162.         }
  163.     }
  164.     /* Look it up in the transport protocol table */
  165.     for(ipp = Iplink;ipp->funct        ;ipp++){
  166.         if(ipp->proto == ip->protocol)
  167.             break;
  168.     }
  169.     if(ipp->funct        ){
  170.         /* Found, call transport protocol */
  171.         (*ipp->funct)(iface,ip,bp,rxbroadcast);
  172.     } else {
  173.         /* Not found */
  174.         if(rxcnt == 0){
  175.             /* Send an ICMP Protocol Unknown response... */
  176.             ipInUnknownProtos++;
  177.             /* ...unless it's a broadcast */
  178.             if(!rxbroadcast){
  179.                 icmp_output(ip,bp,ICMP_DEST_UNREACH,
  180.                  ICMP_PROT_UNREACH,NULLICMP);
  181.             }
  182.         }
  183.         free_p(bp);
  184.     }
  185. }
  186. /* Handle IP packets encapsulated inside IP */
  187. void
  188. ipip_recv(iface,ip,bp,rxbroadcast)
  189. struct iface *iface;    /* Incoming interface */
  190. struct ip *ip;          /* Extracted IP header */
  191. struct mbuf *bp;        /* Data portion */
  192. int rxbroadcast;        /* True if received on subnet broadcast address */
  193. {
  194.     struct phdr phdr;
  195.     struct mbuf *tbp;
  196.  
  197.     if((tbp = pushdown(bp,sizeof(phdr))) == NULLBUF){
  198.         free_p(bp);
  199.         return;
  200.     }
  201.     bp = tbp;
  202.     phdr.iface = &Encap;
  203.     phdr.type = CL_NONE;
  204.     memcpy(&bp->data[0],(char *)&phdr,sizeof(phdr));
  205.     enqueue(&Hopper,bp);
  206. }
  207.  
  208. /* Process IP datagram fragments
  209.  * If datagram is complete, return it with ip->length containing the data
  210.  * length (MINUS header); otherwise return NULLBUF
  211.  */
  212. static
  213. struct mbuf *
  214. fraghandle(ip,bp)
  215. struct ip *ip;          /* IP header, host byte order */
  216. struct mbuf *bp;        /* The fragment itself */
  217. {
  218.     register struct reasm *rp; /* Pointer to reassembly descriptor */
  219.     struct frag *lastfrag,*nextfrag,*tfp;
  220.     struct mbuf *tbp;
  221.     int16 i;
  222.     int16 last;             /* Index of first byte beyond fragment */
  223.  
  224.     last = ip->offset + ip->length - (IPLEN + ip->optlen);
  225.  
  226.     rp = lookup_reasm(ip);
  227.     if(ip->offset == 0 && !ip->flags.mf){
  228.         /* Complete datagram received. Discard any earlier fragments */
  229.         if(rp != NULLREASM){
  230.             free_reasm(rp);
  231.             ipReasmOKs++;
  232.         }
  233.         return bp;
  234.     }
  235.     ipReasmReqds++;
  236.     if(rp == NULLREASM){
  237.         /* First fragment; create new reassembly descriptor */
  238.         if((rp = creat_reasm(ip)) == NULLREASM){
  239.             /* No space for descriptor, drop fragment */
  240.             ipReasmFails++;
  241.             free_p(bp);
  242.             return NULLBUF;
  243.         }
  244.     }
  245.     /* Keep restarting timer as long as we keep getting fragments */
  246.     stop_timer(&rp->timer);
  247.     start_timer(&rp->timer);
  248.  
  249.     /* If this is the last fragment, we now know how long the
  250.      * entire datagram is; record it
  251.      */
  252.     if(!ip->flags.mf)
  253.         rp->length = last;
  254.  
  255.     /* Set nextfrag to the first fragment which begins after us,
  256.      * and lastfrag to the last fragment which begins before us
  257.      */
  258.     lastfrag = NULLFRAG;
  259.     for(nextfrag = rp->fraglist;nextfrag != NULLFRAG;nextfrag = nextfrag->next){
  260.         if(nextfrag->offset > ip->offset)
  261.             break;
  262.         lastfrag = nextfrag;
  263.     }
  264.     /* Check for overlap with preceeding fragment */
  265.     if(lastfrag != NULLFRAG  && ip->offset < lastfrag->last){
  266.         /* Strip overlap from new fragment */
  267.         i = lastfrag->last - ip->offset;
  268.         pullup(&bp,NULLCHAR,i);
  269.         if(bp == NULLBUF)
  270.             return NULLBUF; /* Nothing left */
  271.         ip->offset += i;
  272.     }
  273.     /* Look for overlap with succeeding segments */
  274.     for(; nextfrag != NULLFRAG; nextfrag = tfp){
  275.         tfp = nextfrag->next;   /* save in case we delete fp */
  276.  
  277.         if(nextfrag->offset >= last)
  278.             break;  /* Past our end */
  279.         /* Trim the front of this entry; if nothing is
  280.          * left, remove it.
  281.          */
  282.         i = last - nextfrag->offset;
  283.         pullup(&nextfrag->buf,NULLCHAR,i);
  284.         if(nextfrag->buf == NULLBUF){
  285.             /* superseded; delete from list */
  286.             if(nextfrag->prev != NULLFRAG)
  287.                 nextfrag->prev->next = nextfrag->next;
  288.             else
  289.                 rp->fraglist = nextfrag->next;
  290.             if(tfp->next != NULLFRAG)
  291.                 nextfrag->next->prev = nextfrag->prev;
  292.             freefrag(nextfrag);
  293.         } else
  294.             nextfrag->offset = last;
  295.     }
  296.     /* Lastfrag now points, as before, to the fragment before us;
  297.      * nextfrag points at the next fragment. Check to see if we can
  298.      * join to either or both fragments.
  299.      */
  300.     i = INSERT;
  301.     if(lastfrag != NULLFRAG && lastfrag->last == ip->offset)
  302.         i |= APPEND;
  303.     if(nextfrag != NULLFRAG && nextfrag->offset == last)
  304.         i |= PREPEND;
  305.     switch(i){
  306.     case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  307.         tfp = newfrag(ip->offset,last,bp);
  308.         tfp->prev = lastfrag;
  309.         tfp->next = nextfrag;
  310.         if(lastfrag != NULLFRAG)
  311.             lastfrag->next = tfp;   /* Middle of list */
  312.         else
  313.             rp->fraglist = tfp;     /* First on list */
  314.         if(nextfrag != NULLFRAG)
  315.             nextfrag->prev = tfp;
  316.         break;
  317.     case APPEND:    /* Append to lastfrag */
  318.         append(&lastfrag->buf,bp);
  319.         lastfrag->last = last;  /* Extend forward */
  320.         break;
  321.     case PREPEND:   /* Prepend to nextfrag */
  322.         tbp = nextfrag->buf;
  323.         nextfrag->buf = bp;
  324.         append(&nextfrag->buf,tbp);
  325.         nextfrag->offset = ip->offset;  /* Extend backward */
  326.         break;
  327.     case (APPEND|PREPEND):
  328.         /* Consolidate by appending this fragment and nextfrag
  329.          * to lastfrag and removing the nextfrag descriptor
  330.          */
  331.         append(&lastfrag->buf,bp);
  332.         append(&lastfrag->buf,nextfrag->buf);
  333.         nextfrag->buf = NULLBUF;
  334.         lastfrag->last = nextfrag->last;
  335.  
  336.         /* Finally unlink and delete the now unneeded nextfrag */
  337.         lastfrag->next = nextfrag->next;
  338.         if(nextfrag->next != NULLFRAG)
  339.             nextfrag->next->prev = lastfrag;
  340.         freefrag(nextfrag);
  341.         break;
  342.     }
  343.     if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG
  344.         && rp->length != 0){
  345.         /* We've gotten a complete datagram, so extract it from the
  346.          * reassembly buffer and pass it on.
  347.          */
  348.         bp = rp->fraglist->buf;
  349.         rp->fraglist->buf = NULLBUF;
  350.         /* Tell IP the entire length */
  351.         ip->length = rp->length + (IPLEN + ip->optlen);
  352.         free_reasm(rp);
  353.         ipReasmOKs++;
  354.         return bp;
  355.     } else
  356.         return NULLBUF;
  357. }
  358. /* Arrange for receipt of raw IP datagrams */
  359. struct raw_ip *
  360. raw_ip(protocol,r_upcall)
  361. int protocol;
  362. void (*r_upcall)();
  363. {
  364.     register struct raw_ip *rp;
  365.  
  366.     rp = (struct raw_ip *)callocw(1,sizeof(struct raw_ip));
  367.     rp->protocol = protocol;
  368.     rp->r_upcall = r_upcall;
  369.     rp->next = Raw_ip;
  370.     Raw_ip = rp;
  371.     return rp;
  372. }
  373. /* Free a raw IP descriptor */
  374. void
  375. del_ip(rpp)
  376. struct raw_ip *rpp;
  377. {
  378.     struct raw_ip *rplast = NULLRIP;
  379.     register struct raw_ip *rp;
  380.  
  381.     /* Do sanity check on arg */
  382.     for(rp = Raw_ip;rp != NULLRIP;rplast=rp,rp = rp->next)
  383.         if(rp == rpp)
  384.             break;
  385.     if(rp == NULLRIP)
  386.         return; /* Doesn't exist */
  387.  
  388.     /* Unlink */
  389.     if(rplast != NULLRIP)
  390.         rplast->next = rp->next;
  391.     else
  392.         Raw_ip = rp->next;
  393.     /* Free resources */
  394.     free_q(&rp->rcvq);
  395.     free((char *)rp);
  396. }
  397.  
  398. static struct reasm *
  399. lookup_reasm(ip)
  400. struct ip *ip;
  401. {
  402.     register struct reasm *rp;
  403.     struct reasm *rplast = NULLREASM;
  404.  
  405.     for(rp = Reasmq;rp != NULLREASM;rplast=rp,rp = rp->next){
  406.         if(ip->id == rp->id && ip->source == rp->source
  407.          && ip->dest == rp->dest && ip->protocol == rp->protocol){
  408.             if(rplast != NULLREASM){
  409.                 /* Move to top of list for speed */
  410.                 rplast->next = rp->next;
  411.                 rp->next = Reasmq;
  412.                 Reasmq = rp;
  413.             }
  414.             return rp;
  415.         }
  416.  
  417.     }
  418.     return NULLREASM;
  419. }
  420. /* Create a reassembly descriptor,
  421.  * put at head of reassembly list
  422.  */
  423. static struct reasm *
  424. creat_reasm(ip)
  425. register struct ip *ip;
  426. {
  427.     register struct reasm *rp;
  428.  
  429.     if((rp = (struct reasm *)calloc(1,sizeof(struct reasm))) == NULLREASM)
  430.         return rp;      /* No space for descriptor */
  431.     rp->source = ip->source;
  432.     rp->dest = ip->dest;
  433.     rp->id = ip->id;
  434.     rp->protocol = ip->protocol;
  435.     set_timer(&rp->timer,ipReasmTimeout * 1000L);
  436.     rp->timer.func = ip_timeout;
  437.     rp->timer.arg = rp;
  438.  
  439.     rp->next = Reasmq;
  440.     Reasmq = rp;
  441.     return rp;
  442. }
  443.  
  444. /* Free all resources associated with a reassembly descriptor */
  445. static void
  446. free_reasm(r)
  447. struct reasm *r;
  448. {
  449.     register struct reasm *rp;
  450.     struct reasm *rplast = NULLREASM;
  451.     register struct frag *fp;
  452.  
  453.     for(rp = Reasmq;rp != NULLREASM;rplast = rp,rp=rp->next)
  454.         if(r == rp)
  455.             break;
  456.     if(rp == NULLREASM)
  457.         return; /* Not on list */
  458.  
  459.     stop_timer(&rp->timer);
  460.     /* Remove from list of reassembly descriptors */
  461.     if(rplast != NULLREASM)
  462.         rplast->next = rp->next;
  463.     else
  464.         Reasmq = rp->next;
  465.  
  466.     /* Free any fragments on list, starting at beginning */
  467.     while((fp = rp->fraglist) != NULLFRAG){
  468.         rp->fraglist = fp->next;
  469.         free_p(fp->buf);
  470.         free((char *)fp);
  471.     }
  472.     free((char *)rp);
  473. }
  474.  
  475. /* Handle reassembly timeouts by deleting all reassembly resources */
  476. static void
  477. ip_timeout(arg)
  478. void *arg;
  479. {
  480.     register struct reasm *rp;
  481.  
  482.     rp = (struct reasm *)arg;
  483.     free_reasm(rp);
  484.     ipReasmFails++;
  485. }
  486. /* Create a fragment */
  487. static struct frag *
  488. newfrag(offset,last,bp)
  489. int16 offset,last;
  490. struct mbuf *bp;
  491. {
  492.     struct frag *fp;
  493.  
  494.     if((fp = (struct frag *)calloc(1,sizeof(struct frag))) == NULLFRAG){
  495.         /* Drop fragment */
  496.         free_p(bp);
  497.         return NULLFRAG;
  498.     }
  499.     fp->buf = bp;
  500.     fp->offset = offset;
  501.     fp->last = last;
  502.     return fp;
  503. }
  504. /* Delete a fragment, return next one on queue */
  505. static void
  506. freefrag(fp)
  507. struct frag *fp;
  508. {
  509.     free_p(fp->buf);
  510.     free((char *)fp);
  511. }
  512.  
  513. /* In red alert mode, blow away the whole reassembly queue. Otherwise crunch
  514.  * each fragment on each reassembly descriptor
  515.  */
  516. void
  517. ip_garbage(red)
  518. int red;
  519. {
  520.     struct reasm *rp,*rp1;
  521.     struct frag *fp;
  522.     struct raw_ip *rwp;
  523.  
  524.     /* Run through the reassembly queue */
  525.     for(rp = Reasmq;rp != NULLREASM;rp = rp1){
  526.         rp1 = rp->next;
  527.         if(red){
  528.             free_reasm(rp);
  529.         } else {
  530.             for(fp = rp->fraglist;fp != NULLFRAG;fp = fp->next){
  531.                 mbuf_crunch(&fp->buf);
  532.             }
  533.         }
  534.     }
  535.     /* Run through the raw IP queue */
  536.     for(rwp = Raw_ip;rwp != NULLRIP;rwp = rwp->next)
  537.         mbuf_crunch(&rwp->rcvq);
  538. }
  539.